#include <iostream>
#include <iomanip>
#include <fstream>

#include <fcntl.h>

#include "IOError.h"
#include "Counter_DL636G1.h"
#include "DigitalIO_DL636F.h"
#include "TimeCounter_DL643A1.h"
#include "ADC_DL642A.h"

#include <root/TROOT.h>
#include <root/TFile.h>
#include <root/TTree.h>

using namespace std;


const int measure_time = 300000; /* usec */



int main(int argc, char *argv[])
{
  const char *device="/dev/sis1100_00remote";
//   cout << "device: " << device << endl;
  int crate;
  short adc[3];
  unsigned time = 0, dt = 0, prev_time = 0;
  unsigned ev_counter = 0;	

  cout << "dackel 0.0.0" << endl << endl;
  
  // open sis1100/3100 pci-to-vme link
  if( !(crate=open(device, O_RDWR, 0)) ) {
    cout << "ERROR: could not open \"" << device << "\"" << endl;
    exit(1);
  }
  
  vmesysreset(crate);

  // instantiate counter object
  Counter_DL636G1 counter1(crate,0x8820);

  // instantiate io object
  DigitalIO_DL636F io1(crate,0x8800);

  TimeCounter_DL643A1 tc1(crate, 0x8860);
  
  // instantiate adc object
  ADC_DL642A adc1(crate,0xb400);
  
  
  	
  string filename = "adc_test.dat";
  cout << "saving results to " << filename << "..." << endl;		
  ofstream f(filename.c_str(), ios::trunc);
	
  // init root file
  TFile rf("adc_test.root", "recreate");
  TTree * tree = new TTree("Data", "Data");
  tree->Branch("adc", &(adc[0]), "adc[3]/S");
  tree->Branch("time", &(time), "time/I");
  tree->Branch("dt", &(dt), "dt/I");
	

 try {
	  
	tc1.reset();
	  
	counter1.reset();
	
	// output counter values
	cout << "counter1.a == " << counter1.getA() << endl;
	cout << "counter1.b == " << counter1.getB() << endl;
	cout << "counter1.c == " << counter1.getC() << endl << endl;
	
	// init adc1.
	cout << "adc1: init" << endl;
	adc1.reset();
	adc1.clearFIFO();
	adc1.setEnabled(1);
	
	// display current state of adc1
	cout << "adc:"
		<< " hitcounter = " << adc1.getHitCounter()
		<< " enable = " << adc1.isEnabled() 
		<< " status = " << setw(4) << setfill('0') << adc1.getStatus()
		<< " busy = " << io1.getInput() << endl;

	for (unsigned loops = 0; loops < 100; loops++) {
	
		// enable gate of adc1 via output 1 of io1
		cout << "enabling gate of adc1" << endl; 
		io1.setO1(1);
	
		cout << "measuring...";
		for (int i= 0; i < 10; i++) {
			usleep(measure_time / 10);
			cout << "." << flush;
		}
		cout << endl;
		
		// disable gate of adc1 via output 1 of io1
		cout << "gate of adc1 disabled" << endl; 
		io1.setO1(0);

		// display current state of adc1
		cout << "adc:"
				<< " events = " << adc1.getHitCounter()
				<< " enable = " << adc1.isEnabled() 
				<< " status = " << setw(4) << hex << setfill('0') << adc1.getStatus()
				<< " busy = " << dec << io1.getInput() << endl;
		cout << "timer:" 
				<< " hitcounter = " << tc1.getWords()
				<< " status = " << setw(4) << setfill('0') << hex << tc1.getStatus()
				<< endl;
		
		// save results
		for (unsigned i = 0; i < adc1.getHitCounter(); i++) {
			adc[0] = adc1.readFIFO32(0);
			adc[1] = adc1.readFIFO32(1);
			adc[2] = adc1.readFIFO32(2);
			time = tc1.readFIFO();
			dt = time - prev_time;
		
			f << i << " " << adc[0] << " " << adc[1] << " "<< adc[2] << " " << time << " " << dt << endl;
			tree->Fill();
			prev_time = time;
		}
		
		// FIXME: why do we need to reset / clear the FIFOs??
		// answer: because they're nor decremented during read-out of the FIFOs
		adc1.clearHitCounter();
//		adc1.clearFIFO();
		tc1.reset();
	}
		
	
	
	f.close();
	rf.Write();
	rf.Close();
	
			
	// output counter values
    cout << "counter1.a == " << counter1.getA() << endl;
    cout << "counter1.b == " << counter1.getB() << endl;
    cout << "counter1.c == " << counter1.getC() << endl << endl;
                
    usleep(100);
  }
  catch( IOError ioe ) {
    cout << "catched IOError expection: " << ioe.getMsg() << endl 
	 << "param=" << ioe.getParam() << endl;
  }
    

  close(crate);

  return 0;
}
